package com.qianji.petmall.search.thread;

import java.util.concurrent.*;

/**
 * @author liang zai
 * @date 2022/3/4 16:10
 * @description
 */
public class ThreadTest {
    //创建10个线程
    //TODO 第一种初始化线程池的方法
    public static final ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main......start");
        /**
         * 创建异步对象 runAsync|supplyAsync
         */
        //TODO 没有返回值的
//        CompletableFuture<Void> future = CompletableFuture.runAsync(new Thread02(), service);
        //TODO 有返回值的
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getName());
//            int i = 10 / 0;
//            System.out.println("运行结果" + i);
//            return i;
//        }, service).whenComplete((t,u) -> {
//            //虽然能捕获异常，但是不能返回数据
//            System.out.println("异步任务完成....感知到返回值为:"+t+"异常类型是:"+u);
//        }).exceptionally(throwable -> {
//            //可以感知异常并返回一个默认的值
//            return 10;
//        });
        /**
         * 最终处理 handle 方法
         */
        //TODO 统一的结果处理
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getName());
//            int i = 10 / 0;
//            System.out.println("运行结果" + i);
//            return i;
//        }, service).handle((ref,fn) ->{
//            if (fn!=null){
//                return 0;
//            }
//            if (ref != null){
//                return ref*2;
//            }
//            return 0;
//        });
        /**
         * 线程串行化方法
         */
        // TODO thenRun：继续执行，不接受上一个任务的返回结果,自己执行完也没有返回结果
//        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getName());
//            int i = 10 / 2;
//            System.out.println("运行结果" + i);
//        }, service).thenRunAsync(() -> {
//            System.out.println("任务二启动了");
//        },service);
//        System.out.println("返回数据:");
        //TODO thenAccept：继续执行，接受上一个任务的返回结果,自己执行完没有返回结果
//        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getName());
//            int i = 10 / 2;
//            System.out.println("运行结果" + i);
//            return i;
//        }, service).thenAcceptAsync(ref -> {
//            System.out.println("任务二启动了..."+"拿到了上一个结果..."+ref);
//        },service);
//        System.out.println("返回数据:");
        //TODO thenApply：继续执行，感知上一任务的返回结果，并且自己的返回结果也被下一个任务所感知
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getName());
//            int i = 10 / 2;
//            System.out.println("运行结果" + i);
//            return i;
//        }, service).thenApplyAsync((ref) -> {
//            System.out.println("任务二启动了..."+"拿到了上一个结果..."+ref);
//            return ref*2;
//        },service);
//        System.out.println("返回数据:"+future.get());
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程1开始" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("线程1结束....");
            return i;
        },service);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程2开始" + Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程2结束....");
            return "hello";
        },service);
        CompletableFuture<Object> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程3开始" + Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程3结束....");
            return "hello2";
        },service);
        /**
         * 两任务组合 - 都要完成
         */
        //TODO thenAcceptBoth:组合两个future，获取前两个future任务的返回结果，然后处理任务，没有返回值。
//        future1.thenAcceptBothAsync(future2,(f1,f2) -> {
//            System.out.println("线程3开始之前的结果..."+f1+"===>"+f2);
//        },service);
        //TODO thenCombine:组合两个future，获取前两个future的返回结果，并返回当前任务的返回值
//        CompletableFuture<String> future = future1.thenCombineAsync(future2, (f1, f2) -> {
//            return f1 + "=" + f2;
//        }, service);
//        System.out.println("main......end...."+future.get());
//        //TODO runAfterBoth:组合两个future，不需要获取之前任务future的结果，只需两个future处理完任务后，处理该任务。
//        future1.runAfterBothAsync(future2,() -> {
//            System.out.println("线程3执行");
//        },service);
//        /**
//         * 两个任务 - 一个完成
//         */
//        //TODO applyToEither： 两个任务有一个执行完成， 获取它的返回值， 处理任务并有新的返回值。
//        CompletableFuture<String> future = future2.applyToEitherAsync(future1, f1 -> {
//            System.out.println("线程3执行..." + "上次的结果..." + f1);
//            return f1 + "ref";
//        }, service);
//        System.out.println("返回值为:"+future.get());
//        //TODO acceptEither： 两个任务有一个执行完成， 获取它的返回值， 处理任务， 没有新的返回值。
//        future2.acceptEitherAsync(future1,(ref) -> {
//            System.out.println("线程3执行..."+"上次的结果..."+ref);
//        },service);
//        //TODO runAfterEither： 两个任务有一个执行完成， 不需要获取 future 的结果， 处理任务， 也没有返回值。
//        future2.runAfterEitherAsync(future1,()->{
//            System.out.println("线程3执行...");
//        },service);
        /**
         * 多任务组合
         */
        //TODO allOf:等待所有任务完成
        CompletableFuture<Void> future = CompletableFuture.allOf(future1, future2, future3);
        future.get();
        System.out.println("返回的数据:");
        //TODO anyOf:只要有一个完成
//        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2, future3);
//        anyOf.get();//等待其中之一任务完成
//        System.out.println("返回数据:");
    }


    public static void thread(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main......start");
//        Thread01 thread01 = new Thread01();
//        new Thread(thread01).start();
//        Thread02 thread02 = new Thread02();
//        new Thread(thread02).start();
//        Thread03 thread03 = new Thread03();
//        FutureTask futureTask = new FutureTask<>(new Thread03());
//        new Thread(futureTask).start();
//        Integer i = (Integer) futureTask.get();
        //创建线程池
        /**
         * 原生线程池的七大参数
         * corePoolSize：核心线程数【一直存在除非设置时间】，使用到的时候才会给线程池里面添加核心线程
         * maximumPoolSize：最大线程数量；控制资源并发的
         * keepAliveTime：存活时间，如果当前的线程数量大于核心数量；释放空闲的线程
         * unit：时间单位
         * BlockingQueue<Runnable> workQueue：阻塞队列；如果任务很多，就会将目前多的任务放到队列等待；只要有空闲的线程就会依次取出执行
         * threadFactory：线程的创建工厂
         * handler：如果队列满了，按照指定的策略拒绝执行任务
         *
         *
         * 工作顺序：
         *工作顺序：
         * 1)、线程池创建，准备好核数量的核心线程，准备接受任务
         * 1.1、核心满了，就将再进来的任务放入阻塞队列中。空闲的核就会自己去阻塞队列获取任务执行
         * 1.2、阻塞队列满了，就直接开新线程执行，最大只能开到max指定的数量
         * 1.3、max满了就用Rejected ExecutionHandler拒绝任务
         * 1.4、max都执行完成，有很多空闲.在指定的时间以后，释放max-核这些线程
         * 新LinkedBLocleingDeque<>()：默认是Integer的最大值。内存不够
         * 一个线程池核心7，最大20，队列：50,100并发进来怎么分配的；
         * 7个会立即得到执行，50个会进入队列，再开13个进行执行。剩下的3E个就使用拒绝策略.如果不想抛弃还要执行.CalLerRunsPoLice；
         */
        // TODO 第二种初始化线程池的方法
//        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100000),
//                Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
//        FutureTask futureTask = new FutureTask<>(new Thread03());
//        threadPoolExecutor.execute(futureTask);

        System.out.println("main......end");
    }

    public static class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果"+i);
        }
    }
    public static class Thread02 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果"+i);
        }
    }
    public static class Thread03 implements Callable {

        @Override
        public Object call() throws Exception {
            System.out.println("当前线程:"+Thread.currentThread().getName());
            Integer i=10/2;
            System.out.println("运行结果:"+i);
            return i;
        }
    }
}
